#include "kcp_module.h"
#include "kcp_typedef.h"
#include <assert.h>
#include "knet.h"

// Implement GetKcpModule() interface.
namespace KCP {
    IKcpModule* GNAPI GetKcpModule() {
        return &CKCPModule::instance();
    }

    CKCPModule::CKCPModule() : m_ioService(), m_ioServicePool(0), m_ref(0) {
    }

    CKCPModule::~CKCPModule() {
        for (auto &server : m_array) {
            this->stop(server);
        }
        m_array.clear();
    }

    bool CKCPModule::Init() {
        m_ioServicePool.Init();
        return true;
    }

    bool CKCPModule::Run(int count) {
        // io_context poll
        bool busy = true;
        do {
         if (0 == m_ioService.poll_one()) {
             busy = false;
             break;
         }
        } while (--count >= 0);

        // kcp server update.
        for (size_t i = 0; i < m_array.size(); i++) {
            m_array[i]->update();
        }

        return busy;
    }

   IKServer *CKCPModule::Listen(const char *ip, unsigned short port, IKSessionFactory *factory) {
        return this->Create(ip, port, factory, true);
    }

    bool CKCPModule::Connect(const char *ip, unsigned short port, IKSessionFactory *factory) {
        if (ip == nullptr || 0 == strcmp(ip, "0")) {
            ip = "0.0.0.0";
        }
        CKCPServer *server = this->Create(ip, 0, factory, false);
        if (server == nullptr) {
            ADebug("create %s error", ip);
            return false;
        }
        server->sendMsg(ip, port, NEW_CONNECTION, sizeof(NEW_CONNECTION));
        return true;
    }

    CKCPServer *CKCPModule::Create(const std::string &ip, uint16 port, IKSessionFactory *sessionFactory, bool listen) {
        if (sessionFactory == nullptr) {
            ADebug("null session factory");
            return nullptr;
        }

        auto &ioService = m_ioServicePool.GetIoContext();
        CKCPServer *server = new CKCPServer(ioService, ip, port, sessionFactory, listen);
        m_array.push_back(server);
        return server;
    }

    void CKCPModule::stop(CKCPServer *server) {
        if (server == nullptr) {
            return;
        }

        // try to stop server.
        server->stop();

        for (size_t i = 0; i < m_array.size(); i++) {
            if (m_array[i] == server) {
                m_array[i] = nullptr;
                delete server;
                break;
            }
        }
    }
}